package LiuYun

import spinal.core._
import spinal.lib._

class FeCsr extends Bundle{
    val alert    :Bool = Bool()
    def collect(csr:Csr):Unit ={
        alert     := csr.crmd.ie && (csr.ecfg.lie & csr.estat.getIS).orR
    }
}

class BTBSave extends Bundle{
    val hit = Bool()
    val taken = Bool()
    val index = UInt(log2Up(BTBConfig.Count) bits)
}
class StageFe1 extends Component{
    val io = new Bundle{
        val oc:PipeCtrl = master(new PipeCtrl)
        val odat:SDatFe2  = out(new SDatFe2)
        val ireq:InstReq  = master(new InstReq )
        val brbus:BrBus = in(new BrBus)
        val exbus:CoreCancel = in(new CoreCancel)
        val csr:FeCsr = in(new FeCsr)
        val btb:BTBLookup = slave(new BTBLookup)
        val ras   :Ras        = master(new Ras)
    }
    val pc  :UInt = RegInit(LISA.bootPC)
    val ghr :Bits = Reg(Bits(BTBConfig.Ghrwidth bits)) init(0)
    val ex  :Bool = RegInit(False)
    // fetching should be stoped after instruction IDLE
    val idle:Bool = RegInit(False)

    val ic  :PipeCtrl = new PipeCtrl(True,ex)
    val idat:SDatFe1  = new SDatFe1(pc)
    val data:SDatFe2 = new SDatFe2 assignedFrom idat
    val pipe:StageBuffer[SDatFe2] = new StageBuffer[SDatFe2](data)
    val cancel:Bool = Bool()
    pipe.update(ic,io.oc,cancel)
    io.odat := pipe.data

    val buses = Array(io.brbus,io.exbus)
    val seq:UInt = pc + U(4)
    val nextpc:UInt = Mux(io.btb.taken,io.btb.target,seq)
    cancel := buses.map(_.cancel).reduce(_||_)
    when(ic.allow){
        pc := nextpc
        ghr := Mux(io.btb.taken, THR.update(ghr, pc, nextpc), ghr)
    }
    for(bus <- buses){
        pc @=: bus
        ghr @==: bus
    }
    
    when(io.exbus.cancel || io.csr.alert){
        idle := False
    }.elsewhen(io.brbus.cancel){
        idle := io.brbus.idle
    }
    
    val ex_adef:Bool = pc(1 downto 0).orR
    val ex_fast:Bool = ex_adef
    when(cancel){
        ex := False
    }.elsewhen(ic.allow){
        ex := pipe.newex || ex
    }
    pipe.newex := ex_fast
    pipe.ready := io.ireq.allow && !idle
    data.ecode := LISA.Ex.ADEF.code
    
    io.ireq.valid  := !ex_fast && pipe.maygo && !idle
    io.ireq.va     := pc

    io.ras.target := seq
    //io.ras.push := link_to_ra

    io.btb.pc := pc
    io.btb.ghr := ghr
    io.btb.valid := pipe.go
    data.ghr := ghr
    data.predtarget := io.btb.target
    val btbsave = new BTBSave
    btbsave.hit := io.btb.data.hit
    btbsave.taken := io.btb.taken
    btbsave.index := io.btb.data.index
    data.btbsave := btbsave
}
